use crate::types::NodePosition;
use eframe::egui::{Context, Id, Stroke, Vec2};
use eframe::epaint::Color32;
use std::collections::HashMap;

pub const APP_NAME: &str = "十二时辰行为树编辑器";
const CONFIG_ID_SOURCE: &str = "app_config";

#[derive(Clone)]
pub struct AppConfig {
    // 节点相关配置
    pub node_bg_fill_color: Color32,
    pub node_stroke: Stroke,

    // 控制点相关配置
    pub control_point_radius: f32,
    control_point_stroke: Stroke,
    control_point_connected_fill_color: Color32,
    control_point_not_connected_fill_color: Color32,

    // 贝塞尔曲线相关配置
    bezier_draw_fill_color: Color32,
    bezier_draw_stroke: Stroke,
    bezier_connected_map: HashMap<(NodePosition/* start */, NodePosition/* end */), (Color32, Stroke)>,

    // 其他配置
    pub node_spacing: Vec2,
    pub node_padding: Vec2,
    pub node_size: Vec2,
}

impl AppConfig {
    pub fn id() -> Id {
        Id::new(CONFIG_ID_SOURCE)
    }

    pub fn get(ctx: &Context) -> AppConfig {
        ctx.data_mut(|data| {
            data.get_persisted::<Self>(Self::id())
        }).unwrap()
    }

    pub fn set(ctx: &Context) {
        ctx.data_mut(|data| {
            data.get_persisted_mut_or_insert_with::<Self>(
                Self::id(),
                || {
                    Self::default()
                },
            );
        });
    }

    pub fn get_control_point_fill_color_and_stroke(&self, connected: bool) -> (Color32, Stroke) {
        let color = if connected { self.control_point_connected_fill_color }
        else { self.control_point_not_connected_fill_color };
        (color, self.control_point_stroke)
    }

    pub fn get_bezier_fill_color_and_stroke(&self, start_node_position: NodePosition, end_node_position: NodePosition, connected: bool) -> (Color32, Stroke) {
        match !connected {
            true => (self.bezier_draw_fill_color, self.bezier_draw_stroke),
            false => *self.bezier_connected_map.get(&(start_node_position, end_node_position)).unwrap(),
        }
    }

    fn get_bezier_connected_map() -> HashMap<(NodePosition, NodePosition), (Color32, Stroke)> {
        let mut map = HashMap::new();
        map.insert(
            (NodePosition::Parent, NodePosition::Child),
            (Color32::TRANSPARENT, Stroke { width: 2.0, color: Color32::BLACK })
        );
        map.insert(
            (NodePosition::Parent, NodePosition::Current),
            (Color32::TRANSPARENT, Stroke { width: 2.0, color: Color32::ORANGE })
        );
        map.insert(
            (NodePosition::Current, NodePosition::Child),
            (Color32::TRANSPARENT, Stroke { width: 2.0, color: Color32::BLUE })
        );
        map.insert(
            (NodePosition::Current, NodePosition::Relate),
            (Color32::TRANSPARENT, Stroke { width: 2.0, color: Color32::DARK_GREEN })
        );
        map
    }
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            node_bg_fill_color: Color32::WHITE,
            node_stroke: Stroke {
                width: 1.0,
                color: Color32::RED,
            },
            control_point_radius: 5.0,
            control_point_stroke: Stroke {
                width: 1.0,
                color: Color32::RED,
            },
            control_point_connected_fill_color: Color32::GREEN,
            control_point_not_connected_fill_color: Color32::RED,
            bezier_draw_fill_color: Color32::TRANSPARENT,
            bezier_draw_stroke: Stroke {
                width: 2.0,
                color: Color32::GOLD,
            },
            bezier_connected_map: Self::get_bezier_connected_map(),
            node_spacing: Vec2::new(200.0, 100.0),
            node_padding: Vec2::splat(10.),
            node_size: Vec2::new(100., 50.),
        }
    }
}
